package com.plum.admin.config.interceptor;

import cn.hutool.core.util.StrUtil;
import com.google.common.util.concurrent.RateLimiter;
import com.plum.admin.common.annotation.RaterLimit;
import com.plum.admin.common.constant.Constant;
import com.plum.admin.common.exception.BaseException;
import com.plum.admin.common.limit.RedisRateLimiter;
import com.plum.admin.common.util.IpUtil;
import com.plum.admin.config.properties.IpLimitProperties;
import com.plum.admin.config.properties.RateLimitProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * TODO
 *
 * @author 子丶沫
 * @version 1.0
 * @date 2021/9/28 10:01
 */
@Component
@Slf4j
public class LimiterInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisRateLimiter redisRateLimiter;
    @Autowired
    private RateLimitProperties rateLimitProperties;
    @Autowired
    private IpLimitProperties ipLimitProperties;
    @Autowired
    private IpUtil ipUtil;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ip=ipUtil.getIpAddr(request);
        if(ipLimitProperties.isEnable()){
            boolean acquire = redisRateLimiter.redisAcquire(ip, ipLimitProperties.getLimit(), ipLimitProperties.getTimeout());
            if(!acquire){
                throw new BaseException("单身多久了,手速这么快");
            }
        }
        if(rateLimitProperties.isEnable()){
            boolean acquire = redisRateLimiter.redisAcquire(Constant.LIMIT_ALL, rateLimitProperties.getLimit(), rateLimitProperties.getTimeout());
            if(!acquire){
                throw new BaseException("单身多久了,手速这么快");
            }
        }
        try {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Object bean = handlerMethod.getBean();
            Method method = handlerMethod.getMethod();
            RaterLimit rateLimiter = method.getAnnotation(RaterLimit.class);
            if (rateLimiter != null) {
                String name = rateLimiter.name();
                Long limit = rateLimiter.rate();
                Long timeout = rateLimiter.rateInterval();
                if(StrUtil.isBlank(name)){
                    name = StrUtil.subBefore(bean.toString(), "@", false) + "_" + method.getName();
                }
                if (rateLimiter.ipLimit()) {
                    name += "_" + ip;
                }
                Boolean token3 = redisRateLimiter.redisAcquire(name, limit, timeout);
                if (!token3) {
                    throw new BaseException("当前访问人数太多啦，请稍后再试");
                }
            }
        } catch (BaseException e) {
            throw new BaseException(e.getMessage());
        } catch (Exception e) {

        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
